package com.wxjfkg.activiti;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.spring.autodeployment.AbstractAutoDeploymentStrategy;
import org.apache.commons.io.FilenameUtils;
import org.springframework.core.io.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

public class ConditionalDeploymentStrategy extends
		AbstractAutoDeploymentStrategy {

	public static final String DEPLOYMENT_MODE = "conditional";

	private Map<String, String> mapping = new HashMap<String, String>();

	@Override
	public void deployResources(String deploymentNameHint,
			Resource[] resources, RepositoryService repositoryService) {
		for (final Resource resource : resources) {
			final String resourceName = determineResourceName(resource);
			if (resourceName.endsWith("xml")) {
				String key = getBpmnFilename(resourceName);
				String value = getProcessKey(resource);
				mapping.put(key, value);
			}
		}

		ProcessDefinitionQuery processQuery = repositoryService
				.createProcessDefinitionQuery();
		final DeploymentBuilder deploymentBuilder = repositoryService
				.createDeployment().enableDuplicateFiltering()
				.name(deploymentNameHint);

		for (final Resource resource : resources) {
			final String resourceName = determineResourceName(resource);

			String processKey = null;
			if (resource.getFilename().endsWith("png")) {
				processKey = mapping.get(getBpmnFilename(resourceName));
			} else {
				processKey = getProcessKey(resource);
			}

			processQuery = processQuery.processDefinitionKey(processKey);
			List<ProcessDefinition> resultList = processQuery.list();
			if (resultList == null || resultList.isEmpty()) {

				try {
					if (resourceName.endsWith(".bar")
							|| resourceName.endsWith(".zip")
							|| resourceName.endsWith(".jar")) {
						deploymentBuilder.addZipInputStream(new ZipInputStream(
								resource.getInputStream()));
					} else {
						deploymentBuilder.addInputStream(resourceName,
								resource.getInputStream());
					}
				} catch (IOException e) {
					throw new ActivitiException(
							"couldn't auto deploy resource '" + resource
									+ "': " + e.getMessage(), e);
				}
			}
		}
	}

	private String getProcessKey(Resource resource) {
		XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setValidating(false);
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(resource.getInputStream());
			Node node = (Node) xpath.evaluate("//process", doc,
					XPathConstants.NODE);
			NamedNodeMap nnm = node.getAttributes();
			Node attr = nnm.getNamedItem("id");
			return attr.getNodeValue();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	private String getBpmnFilename(String filename) {
		String result = FilenameUtils.getBaseName(filename);
		int index = result.indexOf(".");
		if (index > 0) {
			result = result.substring(0, index);
		}
		return result;
	}

	@Override
	protected String getDeploymentMode() {
		return DEPLOYMENT_MODE;
	}

}
